#pragma once
#include "../Util/util.hpp"
#include <mutex>
#include <assert.h>
#include <stdlib.h>

#define g_host "127.0.0.1"
#define g_user "yss"
#define g_passwd "313710"
#define g_db "mytestdb"
#define g_port 3306

// 用户登录注册
class user_table
{
private:
    MYSQL *_mysql;
    std::mutex _mutex;
public:
    user_table(const std::string& host, const std::string& user, const std::string& passwd,
        const std::string& db, int port)
    {
        _mysql = Mysql_Util::mysql_create(host.c_str(),user.c_str(),passwd.c_str(),db.c_str(),port);
        assert(_mysql != NULL);
    }
    ~user_table()
    {
        Mysql_Util::mysql_des(_mysql);
        _mysql == NULL;
    }

    // 注册
    bool insert(const std::string& username, const std::string& password, const std::string& phone, 
        const std::string& email, const std::string& address)
    {
#define INSERT_USER "insert into user values(NULL, '%s', '%s', '%s', '%s', '%s');"
        char sql[4096] = {0};
        sprintf(sql, INSERT_USER, username.c_str(), password.c_str(), phone.c_str(), email.c_str(), address.c_str());
        bool ret = Mysql_Util::mysql_exe(_mysql, sql);
        if(ret == false)
        {
            LOG(ERROR) << "注册失败..." << "\n";
            return false;
        }
        LOG(INFO) << "注册成功..." << "\n";
        return true;
    }

    // 登录
    bool login(const std::string& username, const std::string& password)
    {
#define LOGIN_USER "select id from user where username='%s' and password='%s';"
        if(username.empty() || password.empty())
        {
            LOG("ERROR") << "请输入用户名或密码" << "\n";
            return false; 
        }
        char sql[4096] = {0};
        sprintf(sql, LOGIN_USER, username.c_str(), password.c_str());
        MYSQL_RES* res = NULL;
        {
            std::unique_lock<std::mutex> lock(_mutex);
            bool ret = Mysql_Util::mysql_exe(_mysql, sql);
            if(ret == false)
            {
                LOG(ERROR) << "登录失败..." << "\n";
                return false;
            }
            res = mysql_store_result(_mysql);
            if(res == NULL)
            {
                LOG(ERROR) << "保存本地失败.." << "\n";
                return false;
            }
        }
        int num_row = mysql_num_rows(res);
        if(num_row != 1)
        {
            LOG(ERROR) << "数据不唯一.." << "\n";
            return false;
        }
        LOG(INFO) << "登录成功..." << "\n";
        return true;
    }
};

// 购物车增删查改
class shop_table
{
private:
    MYSQL *_mysql;
    std::mutex _mutex;
public:
    shop_table(const std::string& host, const std::string& user, const std::string& passwd,
        const std::string& db, int port)
    {
        _mysql = Mysql_Util::mysql_create(host.c_str(),user.c_str(),passwd.c_str(),db.c_str(),port);
        assert(_mysql != NULL);
    }
    ~shop_table()
    {
        Mysql_Util::mysql_des(_mysql);
        _mysql == NULL;
    }

    // 1 增加商品-count默认为1
    bool insert(const std::string& name, double price, int count = 1)
    {
#define INSERT_SHOP "insert into shop values(NULL, '%s', '%lf', '%d');"
        char sql[4096] = {0};
        sprintf(sql, INSERT_SHOP, name.c_str(), price, count);
        bool ret = Mysql_Util::mysql_exe(_mysql, sql);
        if(ret == false)
        {
            LOG(ERROR) << "插入失败..." << "\n";
            return false;
        }
        LOG(INFO) << "插入成功..." << "\n";
        return true;
    }

    // 2 查询-显示所有信息
    bool showAll(string& out)
    {
        const string sql = "select * from shop";
        MYSQL_RES* res = NULL;
        {
            std::unique_lock<std::mutex> lock(_mutex);
            bool ret = Mysql_Util::mysql_exe(_mysql, sql);
            if(ret == false)
            {
                LOG(ERROR) << "查询失败..." << "\n";
                return false;
            }
            res = mysql_store_result(_mysql);
            if(res == NULL)
            {
                LOG(ERROR) << "保存本地失败.." << "\n";
                return false;
            }
        }
        MYSQL_ROW row; // 获取数据
        int num_row = mysql_num_rows(res); // 行
        int num_col = mysql_num_fields(res); // 列
        if (num_row == 0) 
        {
            LOG(INFO) << "没有查询到数据..." << "\n";
            mysql_free_result(res);
            return false;
        }
        for(int i=0; i < num_row; i++)
        {
            row = mysql_fetch_row(res);
            for(int j=0; j<num_col; j++)
            {
                out += row[j];
                out += "    ";
            }
            out += "\n";
        }
        mysql_free_result(res);
        LOG(INFO) << "查询成功..." << "\n";
        return true;
    }

    // 3 查询-根据id
    bool showById(int id, string& out)
    {
#define SHOW_BY_ID "select name, price, count from shop where id = '%d';"
        char sql[4096] = {0};
        sprintf(sql, SHOW_BY_ID, id);
        MYSQL_RES* res = NULL;
        {
            std::unique_lock<std::mutex> lock(_mutex);
            bool ret = Mysql_Util::mysql_exe(_mysql, sql);
            if(ret == false)
            {
                LOG(ERROR) << "查询失败..." << "\n";
                return false;
            }
            res = mysql_store_result(_mysql);
            if(res == NULL)
            {
                LOG(ERROR) << "保存本地失败.." << "\n";
                return false;
            }
        }
        int num_row = mysql_num_rows(res);
        if(num_row != 1)
        {
            LOG(ERROR) << "数据不唯一.." << "\n";
            return false;
        }
        MYSQL_ROW row = mysql_fetch_row(res);
        out += to_string(id);
        out += "    ";
        out += row[0];
        out += "    ";
        out += row[1];
        out += "    ";
        out += row[2];
        out += "\n";
        LOG(INFO) << "查询成功..." << "\n";
        return true;
    }

    // 4 查询-根据名称
    bool showByName(const string& name, string& out)
    {
#define SHOW_BY_NAME "select id, price, count from shop where name = '%s';"
        char sql[4096] = {0};
        sprintf(sql, SHOW_BY_NAME, name.c_str());
        MYSQL_RES* res = NULL;
        {
            std::unique_lock<std::mutex> lock(_mutex);
            bool ret = Mysql_Util::mysql_exe(_mysql, sql);
            if(ret == false)
            {
                LOG(ERROR) << "查询失败..." << "\n";
                return false;
            }
            res = mysql_store_result(_mysql);
            if(res == NULL)
            {
                LOG(ERROR) << "保存本地失败.." << "\n";
                return false;
            }
        }
        int num_row = mysql_num_rows(res);
        if(num_row != 1)
        {
            LOG(ERROR) << "数据不唯一.." << "\n";
            return false;
        }
        MYSQL_ROW row = mysql_fetch_row(res);
        out += row[0];
        out += "    ";
        out += name;
        out += "    ";
        out += row[1];
        out += "    ";
        out += row[2];
        out += "\n";
        LOG(INFO) << "查询成功..." << "\n";
        return true;
    }

    // 5 删除商品-根据id
    bool deleteById(int id)
    {
#define DELETE_BY_ID "delete from shop where id='%d';"
        char sql[4096] = {0};
        sprintf(sql, DELETE_BY_ID, id);
        bool ret = Mysql_Util::mysql_exe(_mysql, sql);
        if(ret == false)
        {
            LOG(ERROR) << "删除失败..." << "\n";
            return false;
        }
        LOG(INFO) << "删除成功..." << "\n";
        return true;
    }

    // 6 删除商品-根据名称
    bool deleteByName(const string& name)
    {
#define DELETE_BY_NAME "delete from shop where name='%s';"
        char sql[4096] = {0};
        sprintf(sql, DELETE_BY_NAME, name.c_str());
        bool ret = Mysql_Util::mysql_exe(_mysql, sql);
        if(ret == false)
        {
            LOG(ERROR) << "删除失败..." << "\n";
            return false;
        }
        LOG(INFO) << "删除成功..." << "\n";
        return true;
    }


    // 7 修改商品-修改数量
    bool update_count(const string& name, int count_off)
    {
#define UPDATE_COUNT "update shop set count=count+'%d' where name='%s';"
        char sql[4096] = {0};
        sprintf(sql, UPDATE_COUNT, count_off, name.c_str());
        bool ret = Mysql_Util::mysql_exe(_mysql, sql);
        if(ret == false)
        {
            LOG(ERROR) << "修改失败..." << "\n";
            return false;
        }
        LOG(INFO) << "修改成功..." << "\n";
        return true;
    }
};